package schedulers

import (
	"gitee.com/shoyer/framework/ctx/session"
	"gitee.com/shoyer/framework/keys"
	"gitee.com/shoyer/service/rdb"
	"gitee.com/shoyer/util"

	"gitee.com/shoyer/logger"

	"github.com/robfig/cron"
)

// ClearSession 清理redis中的超时数据，防止无用数据内存被长期占用
func ClearSession() {
	c := cron.New()

	logger.PanicErrIfNotNil(c.AddFunc("3 */6 * * * *", func() {
		clearSession()
	}))

	c.Start()
}

// 查找遍历session中的数据，到online中查找，如果没有找到，就清除掉。
func clearSession() {
	redis := rdb.GetDB()
	var start uint64
	for {
		// 扫描所有的session key.
		keyss, cursor, err := redis.Scan(start, "f_session_sid_*", 1000).Result()
		if err != nil {
			logger.Error(err.Error())
			break
		}

		// handle keys
		for i := 0; i < len(keyss); i++ {
			key := keyss[i]
			// 通过key, 拿到sid, 查出session.
			sion := session.GetSessionBySessionID(util.Split(key, "_")[3])
			if sion == nil {
				redis.Del(key)
				continue
			}

			if !sion.IsMySession() { // 在master上，这个session有可能是用来作唯一检测的，不是master自己创建的，master不能自己清除它。
				continue
			}

			if util.GetMillisecond()-sion.UpdatedAt <= 3600*1000 { // 超过一个小时没有更新的sesson, 认为是无效的，需要清理掉。
				continue
			}

			// 拿到这个session 的uid, 找到在线的session.
			sessionIDOnLine, err := redis.Get(rdb.GetKey(keys.Online, sion.UID)).Result()
			if err != nil {
				logger.Warn(err)
				// 没有找到在线key,玩家已经离线，清理session
				redis.HDel(rdb.GetKey(keys.SessionByUID), util.UintToString(sion.UID))
				redis.Del(rdb.GetKey(keys.Session, sion.ID))
				rdb.GetMaster().Del(rdb.GetKey(keys.Session, sion.ID))
				rdb.GetMaster().HDel(rdb.GetKey(keys.UserLocatedServerBySid), sion.ID)
				continue
			}

			if sessionIDOnLine != key {
				// 找到在线key，但是不是同一个key, 把当前这个key清除掉
				logger.Infof("key not match, clear")
				redis.Del(rdb.GetKey(keys.Session, sion.ID))
				rdb.GetMaster().Del(rdb.GetKey(keys.Session, sion.ID))
				rdb.GetMaster().HDel(rdb.GetKey(keys.UserLocatedServerBySid), sion.ID)
			}
		}

		if cursor == 0 {
			break
		}

		start = cursor
	}
}
